#ifndef NBDSRV_H
#define NBDSRV_H

#include <stdbool.h>
#include <stdint.h>

#include <sys/socket.h>
#include <sys/types.h>
#include "nbd.h"
#include "exp_async_io.h"
#include "nbd_server.h"

/* Structures */

/**
  * Variables associated with a client connection
  */
typedef struct _client {
    uint64_t exportsize;    /**< size of the file we're exporting */
    char *clientname;    /**< peer, in human-readable format */
    struct sockaddr_storage clientaddr; /**< peer, in binary format, network byte order */
    char *exportname;    /**< (processed) filename of the file we're exporting */

    int net;         /**< The actual client socket */
    SERVER *server;         /**< The server this client is getting data from */

    struct exp_async_io exp_io;

    int clientfeats;     /**< Features supported by this client */
    pthread_mutex_t lock; /**< socket lock */
    void *tls_session; /**< TLS session context. Is NULL unless STARTTLS has been negotiated. */

    void (*socket_closed)(struct _client *);
} CLIENT;

/**
 * Variables associated with an open file
 **/
typedef struct {
    int fhandle;      /**< file descriptor */
    off_t startoff;   /**< starting offset of this file */
} FILE_INFO;

/* Constants and macros */

/**
 * Error domain common for all NBD server errors.
 **/
#define NBDS_ERR g_quark_from_static_string("server-error-quark")

/**
 * NBD server error codes.
 **/
typedef enum {
    NBDS_ERR_CFILE_NOTFOUND,          /**< The configuration file is not found */
    NBDS_ERR_CFILE_MISSING_GENERIC,   /**< The (required) group "generic" is missing */
    NBDS_ERR_CFILE_KEY_MISSING,       /**< A (required) key is missing */
    NBDS_ERR_CFILE_VALUE_INVALID,     /**< A value is syntactically invalid */
    NBDS_ERR_CFILE_VALUE_UNSUPPORTED, /**< A value is not supported in this build */
    NBDS_ERR_CFILE_NO_EXPORTS,        /**< A config file was specified that does not
                                               define any exports */
    NBDS_ERR_CFILE_INCORRECT_PORT,    /**< The reserved port was specified for an
                                               old-style export. */
    NBDS_ERR_CFILE_DIR_UNKNOWN,       /**< A directory requested does not exist*/
    NBDS_ERR_CFILE_READDIR_ERR,       /**< Error occurred during readdir() */
    NBDS_ERR_CFILE_INVALID_SPLICE,    /**< We can't use splice with the other options
                                               specified for the export. */
    NBDS_ERR_SO_LINGER,               /**< Failed to set SO_LINGER to a socket */
    NBDS_ERR_SO_REUSEADDR,            /**< Failed to set SO_REUSEADDR to a socket */
    NBDS_ERR_SO_KEEPALIVE,            /**< Failed to set SO_KEEPALIVE to a socket */
    NBDS_ERR_GAI,                     /**< Failed to get address info */
    NBDS_ERR_SOCKET,                  /**< Failed to create a socket */
    NBDS_ERR_BIND,                    /**< Failed to bind an address to socket */
    NBDS_ERR_LISTEN,                  /**< Failed to start listening on a socket */
    NBDS_ERR_SYS,                     /**< Underlying system call or library error */
    NBDS_ERR_CFILE_INVALID_WAIT,      /**< We can't use wait with the other options
                                               specified for the export. */
} NBDS_ERRS;

/**
  * Logging macros.
  *
  * @todo remove this. We should use g_log in all cases, and use the
  * logging mangler to redirect to syslog if and when necessary.
  */
#ifdef ISSERVER
#define msg(prio, ...) syslog(prio, __VA_ARGS__)
#else
#define msg(prio, ...)
#endif
#define MY_NAME "nbd_server"

/** Per-export flags: */
#define F_READONLY 1      /**< flag to tell us a file is readonly */
#define F_MULTIFILE 2      /**< flag to tell us a file is exported using -m */
#define F_COPYONWRITE 4      /**< flag to tell us a file is exported using
			    copyonwrite */
#define F_AUTOREADONLY 8  /**< flag to tell us a file is set to autoreadonly */
#define F_SPARSE 16      /**< flag to tell us copyronwrite should use a sparse file */
#define F_SDP 32      /**< flag to tell us the export should be done using the Socket Direct Protocol for RDMA */
#define F_SYNC 64      /**< Whether to fsync() after a write */
#define F_FLUSH 128      /**< Whether server wants FLUSH to be sent by the client */
#define F_FUA 256      /**< Whether server wants FUA to be sent by the client */
#define F_ROTATIONAL 512  /**< Whether server wants the client to implement the elevator algorithm */
#define F_TEMPORARY 1024  /**< Whether the backing file is temporary and should be created then unlinked */
#define F_TRIM 2048       /**< Whether server wants TRIM (discard) to be sent by the client */
#define F_FIXED 4096      /**< Client supports fixed new-style protocol (and can thus send us extra options */
#define F_TREEFILES 8192  /**< flag to tell us a file is exported using -t */
#define F_FORCEDTLS 16384 /**< TLS is required, either for the server as a whole or for a given export */
#define F_SPLICE 32768      /**< flag to tell us to use splice for read/write operations */
#define F_WAIT 65536      /**< flag to tell us to wait for file creation */

/* Functions */

#endif //NBDSRV_H
